#include <QFile>
#include <QMessageBox>
#include <QTextStream>

#include "hbot.h"
#include "sdefs.h"
#include "xmlconfig.h"

CXMLConfig::CXMLConfig(const QString &fileName)
{
	m_FileName = fileName;
	Read();
}

CXMLConfig::~CXMLConfig()
{

}

void CXMLConfig::ChangeProfileName(const QString &currentName, const QString &changedName)
{
	m_ErrorXML = XMLCONFIG_ERROR_SUCCESS;
	QDomNode profile = m_RootElement.firstChildElement("profile");
	
	if (!profile.isNull())
	{
		while (!profile.isNull())
		{
			if (profile.attributes().namedItem("name").nodeValue() == currentName)
			{
				break;
			}

			profile = profile.nextSiblingElement("profile");
		}

		if (profile.isNull())
		{
			m_ErrorXML = XMLCONFIG_ERROR_PROFILENONEXISTENT;
			m_ErrorString = currentName;
			ErrorCheck();
			return;
		}
	}
	else
	{
		m_ErrorXML = XMLCONFIG_ERROR_PROFILETAGNONEXISTENT;
		m_ErrorString = currentName;
		ErrorCheck();
		return;
	}
	
	QDomElement oldProfile = profile.toElement();
	QDomElement newProfile = m_DomDocument.createElement("profile");
	newProfile.setAttribute("name", changedName);
	m_RootElement.replaceChild(newProfile, oldProfile);

	Write();
}

void CXMLConfig::CreateProfile(const QString &name)
{
	QDomElement profile = m_DomDocument.createElement("profile");
	profile.setAttribute("name", name);
	m_RootElement.appendChild(profile);
	Write();
}

void CXMLConfig::DeleteProfile(const QString &name)
{
	m_ErrorXML = XMLCONFIG_ERROR_SUCCESS;
	QDomNode profile = m_RootElement.firstChildElement("profile");

	while (!profile.isNull())
	{
		if (profile.attributes().namedItem("name").nodeValue() == name)
		{
			break;
		}

		profile = profile.nextSiblingElement();
	}

	if (profile.isNull())
	{
		m_ErrorXML = XMLCONFIG_ERROR_DELETEPROFILE;
		m_ErrorString = name;
		ErrorCheck();
		return;
	}

	m_RootElement.removeChild(profile);
	Write();
}

void CXMLConfig::ErrorCheck()
{
	switch (GetErrorXML())
	{
	case XMLCONFIG_ERROR_SUCCESS:
	#ifdef _DEBUG
		/*
			Enable this next line if you want to know whether or not it's working. However, when you go to edit a profile,
			this message will spam a LOT simply because it's sending a message for each value saved.
		*/
		//QMessageBox::information(g_HBot.GetPtr(), QObject::tr("Debug Information: Profile Manager"), QObject::tr("Information: Successful action from m_XMLConfig."));
	#endif // _DEBUG
		break;

	case XMLCONFIG_ERROR_OPENREAD:
		QMessageBox::critical(g_HBot.GetPtr(), QObject::tr("Critical Error: Profile Manager"), QObject::tr("Error: Cannot open file for reading: %1. %2. Please exit and restart the program.").arg(m_FileName).arg(GetErrorString()));
		break;

	case XMLCONFIG_ERROR_SETCONTENT:
		QMessageBox::critical(g_HBot.GetPtr(), QObject::tr("Critical Error: Profile Manager"), QObject::tr("Error: Parse error on file: %1 at line %2, column %3:\n%4\nPlease correct parse error and restart the program.").arg(m_FileName).arg(GetErrorLine()).arg(GetErrorColumn()).arg(GetErrorString()));
		break;

	case XMLCONFIG_ERROR_INVALIDTAGNAME:
		QMessageBox::critical(g_HBot.GetPtr(), QObject::tr("Critical Error: Profile Manager"), QObject::tr("Error: Invalid root nodename. File: %1 root nodename is: %2, the correct root nodename is: %3. Please correct the root nodename and restart the program.").arg(m_FileName).arg(GetErrorString()).arg(PROFILE_XML_ROOT_TAGNAME));
		break;

	case XMLCONFIG_ERROR_OPENWRITE:
		QMessageBox::critical(g_HBot.GetPtr(), QObject::tr("Critical Error: Profile Manager"), QObject::tr("Error: Cannot open file for writing: %1. %2. Please exit and restart the program.").arg(m_FileName).arg(GetErrorString()));
		break;

	case XMLCONFIG_ERROR_DELETEPROFILE:
		QMessageBox::warning(g_HBot.GetPtr(), QObject::tr("Warning: Profile Manager"), QObject::tr("Warning: Cannot delete profile: %1 in file: %2 because it does not exist. Please exit and restart the program.").arg(GetErrorString()).arg(m_FileName));
		break;

	case XMLCONFIG_ERROR_PROFILETAGNONEXISTENT:
	#ifdef _DEBUG
		QMessageBox::warning(g_HBot.GetPtr(), QObject::tr("Warning: Profile Manager"), QObject::tr("Warning: Node name 'profile' does not exist under root element.").arg(GetErrorString()));
	#endif // _DEBUG

	case XMLCONFIG_ERROR_PROFILENONEXISTENT:
	#ifdef _DEBUG
		QMessageBox::warning(g_HBot.GetPtr(), QObject::tr("Warning: Profile Manager"), QObject::tr("Warning: Profile: %1 does not exist.").arg(GetErrorString()));
	#endif // _DEBUG
		break;

	case XMLCONFIG_ERROR_EMPTYPROFILE:
	#ifdef _DEBUG
		QMessageBox::warning(g_HBot.GetPtr(), QObject::tr("Warning: Profile Manager"), QObject::tr("Warning: Function: %1 has been passed an empty 'profile' string.").arg(GetErrorString()));
	#endif // _DEBUG
		break;

	case XMLCONFIG_ERROR_EMPTYGROUP:
	#ifdef _DEBUG
		QMessageBox::warning(g_HBot.GetPtr(), QObject::tr("Warning: Profile Manager"), QObject::tr("Warning: Function: %1 has been passed an empty 'group' string.").arg(GetErrorString()));
	#endif // _DEBUG
		break;

	case XMLCONFIG_ERROR_EMPTYVALUEELEMENT:
	#ifdef _DEBUG
		QMessageBox::warning(g_HBot.GetPtr(), QObject::tr("Warning: Profile Manager"), QObject::tr("Warning: Function: %1 has been passed an empty 'valueElement' string.").arg(GetErrorString()));
	#endif // _DEBUG
		break;

	case XMLCONFIG_ERROR_EMPTYVALUE:
	#ifdef _DEBUG
		QMessageBox::warning(g_HBot.GetPtr(), QObject::tr("Warning: Profile Manager"), QObject::tr("Warning: Function: %1 has been passed an empty 'value' string.").arg(GetErrorString()));
	#endif // _DEBUG
		break;

	case XMLCONFIG_ERROR_INVALIDPROFILE:
	#ifdef _DEBUG
		QMessageBox::warning(g_HBot.GetPtr(), QObject::tr("Warning: Profile Manager"), QObject::tr("Warning: Function: %1 has been passed a non-existent 'profile' string.").arg(GetErrorString()));
	#endif // _DEBUG
		break;

	default:
		QMessageBox::critical(g_HBot.GetPtr(), QObject::tr("Critical Error: Profile Manager"), QObject::tr("Error: Unknown error code returned: %1 when trying to read: %2. Please exit and restart the program.").arg(GetErrorXML()).arg(m_FileName));
		break;
	}
}

void CXMLConfig::Read()
{
	m_ErrorXML = XMLCONFIG_ERROR_SUCCESS;
	QFile file(m_FileName);

	if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
	{
		m_ErrorXML = XMLCONFIG_ERROR_OPENREAD;
		m_ErrorString = file.errorString();
		ErrorCheck();
		return;
	}

	if (!m_DomDocument.setContent(&file, true, &m_ErrorString, &m_ErrorLine, &m_ErrorColumn))
	{
		file.close();
		m_ErrorXML = XMLCONFIG_ERROR_SETCONTENT;
		ErrorCheck();
		return;
	}

	file.close();

	m_RootElement = m_DomDocument.documentElement();

	if (m_RootElement.nodeName() != PROFILE_XML_ROOT_TAGNAME)
	{
		m_ErrorXML = XMLCONFIG_ERROR_INVALIDTAGNAME;
		m_ErrorString = m_RootElement.nodeName();
		ErrorCheck();
		return;
	}

#ifdef _DEBUG
	ErrorCheck();
#endif // _DEBUG
}

void CXMLConfig::SetDefaultProfile(const QString &profile)
{
	QDomNode defaultProfileNode = m_RootElement.firstChildElement("default_profile");
	QDomElement oldDefaultProfile;

	if (!defaultProfileNode.isNull())
	{
		oldDefaultProfile = defaultProfileNode.toElement();
	}
	else
	{
		QDomElement defaultProfile = m_DomDocument.createElement("default_profile");
		m_RootElement.insertBefore(defaultProfile, m_RootElement.firstChildElement());
		defaultProfileNode = m_RootElement.firstChildElement("default_profile");
	}

	if (defaultProfileNode.hasChildNodes())
	{
		QDomNodeList remove = defaultProfileNode.childNodes();

		for (int i = 0; i < remove.count(); ++i)
		{
			defaultProfileNode.removeChild(remove.item(i));
		}
	}

	defaultProfileNode.toElement().appendChild(m_DomDocument.createTextNode(profile));

	QDomElement newProfile = defaultProfileNode.toElement();
	m_RootElement.replaceChild(newProfile, oldDefaultProfile);
	
	Write();
}

void CXMLConfig::SetProfileValue(const QString &profile, const QString &group, const QString &valueElement, const QString &value, const QString &attrib)
{
	m_ErrorXML = XMLCONFIG_ERROR_SUCCESS;

	if (profile.isNull())
	{
		m_ErrorXML = XMLCONFIG_ERROR_EMPTYPROFILE;
		m_ErrorString = XMLCONFIG_ERROR_FUNCTION_SETVALUE;
		ErrorCheck();
		return;
	}
	
	if (group.isNull())
	{
		m_ErrorXML = XMLCONFIG_ERROR_EMPTYGROUP;
		m_ErrorString = XMLCONFIG_ERROR_FUNCTION_SETVALUE;
		ErrorCheck();
		return;
	}

	if (valueElement.isNull())
	{
		m_ErrorXML = XMLCONFIG_ERROR_EMPTYVALUEELEMENT;
		m_ErrorString = XMLCONFIG_ERROR_FUNCTION_SETVALUE;
		ErrorCheck();
		return;
	}

	if (value.isNull())
	{
		m_ErrorXML = XMLCONFIG_ERROR_EMPTYVALUE;
		m_ErrorString = XMLCONFIG_ERROR_FUNCTION_SETVALUE;
		ErrorCheck();
		return;
	}

	QDomNode profileNode = m_RootElement.firstChildElement("profile");
	QDomElement oldProfile;

	while (!profileNode.isNull())
	{
		if (profileNode.attributes().namedItem("name").nodeValue() == profile)
		{
			oldProfile = profileNode.toElement();
			break;
		}

		profileNode = profileNode.nextSiblingElement("profile");
	}

	if (profileNode.isNull())
	{
		m_ErrorXML = XMLCONFIG_ERROR_INVALIDPROFILE;
		m_ErrorString = XMLCONFIG_ERROR_FUNCTION_SETVALUE;
		ErrorCheck();
		return;
	}

	QDomNode groupNode = profileNode.firstChildElement(group);

	if (groupNode.isNull())
	{
		profileNode.appendChild(m_DomDocument.createElement(group));
		groupNode = profileNode.firstChildElement(group);
	}

	QDomNode valueElementNode = groupNode.firstChildElement(valueElement);

	if (valueElementNode.isNull())
	{
		groupNode.appendChild(m_DomDocument.createElement(valueElement));
		valueElementNode = groupNode.firstChildElement(valueElement);
	}

	if (!attrib.isNull())
	{
		if (valueElementNode.hasAttributes())
		{
			QDomNamedNodeMap remove = valueElementNode.attributes();

			for (int i = 0; i < remove.count(); ++i)
			{
				if (remove.item(i).nodeName() == attrib)
				{
					valueElementNode.toElement().removeAttributeNode(remove.item(i).toAttr());
				}
			}
		}
	}

	if (valueElementNode.hasChildNodes())
	{
		QDomNodeList remove = valueElementNode.childNodes();

		for (int i = 0; i < remove.count(); ++i)
		{
			valueElementNode.removeChild(remove.item(i));
		}
	}

	if (!attrib.isNull())
	{
		valueElementNode.toElement().setAttribute(attrib, value);
	}
	else
	{
		valueElementNode.toElement().appendChild(m_DomDocument.createTextNode(value));
	}

	QDomElement newProfile = profileNode.toElement();
	m_RootElement.replaceChild(newProfile, oldProfile);

	Write();
}

void CXMLConfig::Write()
{
	m_ErrorXML = XMLCONFIG_ERROR_SUCCESS;
	QFile file(m_FileName);

	if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
	{
		m_ErrorXML = XMLCONFIG_ERROR_OPENWRITE;
		m_ErrorString = file.errorString();
		ErrorCheck();
		return;
	}
	
	QTextStream stream(&file);
	m_DomDocument.save(stream, INDENT_SIZE);

	file.close();

#ifdef _DEBUG
	ErrorCheck();
#endif // _DEBUG
}

QString CXMLConfig::GetDefaultProfile() const
{
	QDomNode defaultProfile = m_RootElement.firstChildElement("default_profile");

	if (!defaultProfile.isNull())
	{
		QDomNode textNode = defaultProfile.firstChild();
		
		while (!textNode.isNull())
		{
			if (textNode.isText())
			{
				if (!textNode.nodeValue().isEmpty())
				{
					return textNode.nodeValue();
				}
				else
				{
					return QString();
				}
			}

			textNode = textNode.nextSibling();
		}

		return QString();
	}
	else
	{
		return QString();
	}
}

QString CXMLConfig::GetProfileValue(const QString &defaultVal, const QString &profile, const QString &group, const QString &valueElement, const QString &attrib)
{
	m_ErrorXML = XMLCONFIG_ERROR_SUCCESS;

	if (profile.isNull())
	{
		m_ErrorXML = XMLCONFIG_ERROR_EMPTYPROFILE;
		m_ErrorString = XMLCONFIG_ERROR_FUNCTION_GETVALUE;
		ErrorCheck();
		return defaultVal;
	}
	
	if (group.isNull())
	{
		m_ErrorXML = XMLCONFIG_ERROR_EMPTYGROUP;
		m_ErrorString = XMLCONFIG_ERROR_FUNCTION_GETVALUE;
		ErrorCheck();
		return defaultVal;
	}

	if (valueElement.isNull())
	{
		m_ErrorXML = XMLCONFIG_ERROR_EMPTYVALUEELEMENT;
		m_ErrorString = XMLCONFIG_ERROR_FUNCTION_GETVALUE;
		ErrorCheck();
		return defaultVal;
	}

	QDomNode profileNode = m_RootElement.firstChildElement("profile");

	while (!profileNode.isNull())
	{
		if (profileNode.attributes().namedItem("name").nodeValue() == profile)
		{
			break;
		}

		profileNode = profileNode.nextSiblingElement("profile");
	}

	if (profileNode.isNull())
	{
		m_ErrorXML = XMLCONFIG_ERROR_INVALIDPROFILE;
		m_ErrorString = XMLCONFIG_ERROR_FUNCTION_GETVALUE;
		ErrorCheck();
		return defaultVal;
	}

	QDomNode groupNode = profileNode.firstChildElement(group);

	if (groupNode.isNull())
	{
		return defaultVal;
	}

	QDomNode valueElementNode = groupNode.firstChildElement(valueElement);

	if (valueElementNode.isNull())
	{
		return defaultVal;
	}

	if (!attrib.isNull())
	{
		if (!valueElementNode.toElement().attributes().namedItem(attrib).nodeValue().isEmpty())
		{
			return valueElementNode.toElement().attributes().namedItem(attrib).nodeValue();
		}
		else
		{
			return defaultVal;
		}
	}
	else
	{
		QDomNode textNode = valueElementNode.firstChild();
		
		while (!textNode.isNull())
		{
			if (textNode.isText())
			{
				if (!textNode.nodeValue().isEmpty())
				{
					return textNode.nodeValue();
				}
				else
				{
					return defaultVal;
				}
			}

			textNode = textNode.nextSibling();
		}

		return defaultVal;
	}

	return QString();
}

QStringList CXMLConfig::GetProfiles() const
{
	QStringList items;
	QDomNode node = m_RootElement.firstChildElement("profile");
	
	while (!node.isNull())
	{
		if (!node.attributes().namedItem("name").nodeValue().isNull())
		{
			items.push_back(node.attributes().namedItem("name").nodeValue());
		}

		node = node.nextSiblingElement();
	}

	return items;
}

QVector<int> CXMLConfig::GetNumberBnet(const QString &profile)
{
	m_ErrorXML = XMLCONFIG_ERROR_SUCCESS;

	if (profile.isNull())
	{
		m_ErrorXML = XMLCONFIG_ERROR_EMPTYPROFILE;
		m_ErrorString = XMLCONFIG_ERROR_FUNCTION_GETVALUE;
		ErrorCheck();
		return QVector<int>();
	}

	QDomNode profileNode = m_RootElement.firstChildElement("profile");

	while (!profileNode.isNull())
	{
		if (profileNode.attributes().namedItem("name").nodeValue() == profile)
		{
			break;
		}

		profileNode = profileNode.nextSiblingElement("profile");
	}

	if (profileNode.isNull())
	{
		m_ErrorXML = XMLCONFIG_ERROR_INVALIDPROFILE;
		m_ErrorString = XMLCONFIG_ERROR_FUNCTION_GETVALUE;
		ErrorCheck();
		return QVector<int>();
	}

	QVector<int> battlenetServers;
	QDomNode groupNode;
	
	for (int i = 0; i < 10; ++i)
	{
		groupNode = profileNode.firstChildElement(TAG_PROFILE_BATTLENET + QString::number(i + 1));
		
		if ((!groupNode.isNull()) && (GetProfileValue("0", profile, groupNode.nodeName(), TAG_PROFILE_BATTLENET_ENABLED).toUInt()))
		{
			battlenetServers.push_back(i);
		}
	}

	return battlenetServers;
}
